home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
ab20
/
ab20_archive
/
datacomm
/
xpr
/
xprzmodem-2.51.lzh
/
xprzmodem2.5
/
Zm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-17
|
19KB
|
796 lines
/**********************************************************************
* Z M . C
* ZMODEM protocol primitives
* 01-19-87 Chuck Forsberg Omen Technology Inc
*
* 29 July 89:
* Major overhaul by Rick Huebner for adaptation to Amiga XPR protocol spec
*
* 28 October 89:
* Converted to Lattice C 5.04
*
* 15 November 1991
* Code added to support CRC-32 by William M. Perkins.
**********************************************************************/
#include <proto/all.h>
#include <exec/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "xproto.h"
#include "zmodem.h"
#include "xprzmodem.h"
#include "zcrc.h"
static char *frametypes[] =
{
"Carrier Lost", /* -3 */
"TIMEOUT", /* -2 */
"ERROR", /* -1 */
#define FTOFFSET 3
"ZRQINIT",
"ZRINIT",
"ZSINIT",
"ZACK",
"ZFILE",
"ZSKIP",
"ZNAK",
"ZABORT",
"ZFIN",
"ZRPOS",
"ZDATA",
"ZEOF",
"ZFERR",
"ZCRC",
"ZCHALLENGE",
"ZCOMPL",
"ZCAN",
"ZFREECNT",
"ZCOMMAND",
"ZSTDERR",
"xxxxx"
#define FRTYPES 22 /* Total number of frame types in this array */
/* not including psuedo negative entries */
};
static UBYTE DLE_actions[] =
{
0,0,0,0,0,0,0,0, 0,0,0,0,0,2,0,0, 1,1,0,1,0,0,0,0, 1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,2,0,0, 1,1,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
};
/**********************************************************
* void zsbhdr(struct Vars *v, USHORT type)
*
* Send ZMODEM binary header hdr of type type
**********************************************************/
void zsbhdr(struct Vars *v, USHORT type)
{
UBYTE *hdr = v->Txhdr;
short n;
USHORT crc;
ULONG crc32;
xsendline(v, ZPAD);
xsendline(v, ZDLE);
if (v->Crc32t = v->Txfcs32) /* zsbh32() */
{
xsendline(v, ZBIN32);
zsendline(v, (UBYTE) type);
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "zsbh32: %s %lx\n", frametypes[type + FTOFFSET],
v->Txpos);
dlog(v, v->Msgbuf);
#endif
crc32 = 0xFFFFFFFFL;
crc32 = UPDC32(type, crc32);
for (n = 4; --n >= 0; ++hdr)
{
crc32 = UPDC32((0377 & *hdr), crc32);
zsendline(v, *hdr);
}
crc32 = ~crc32;
for (n = 4; --n >= 0;)
{
zsendline(v, (int) crc32);
crc32 >>= 8;
}
}
else
{
xsendline(v, ZBIN);
zsendline(v, (UBYTE) type);
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "zsbhdr: %s %lx\n", frametypes[type + FTOFFSET],
v->Txpos);
dlog(v, v->Msgbuf);
#endif
crc = updcrc(type, 0);
for (n = 4; --n >= 0; )
{
zsendline(v, *hdr);
crc = updcrc(((USHORT) (*hdr++)), crc);
}
crc = updcrc(((USHORT) 0), crc);
crc = updcrc(((USHORT) 0), crc);
zsendline(v, (UBYTE) (crc >> 8));
zsendline(v, (UBYTE) crc);
}
} /* End of void zsbhdr() */
/**********************************************************
* void zshhdr(struct Vars *v, USHORT type)
*
* Send ZMODEM HEX header hdr of type type
**********************************************************/
void zshhdr(struct Vars *v, USHORT type)
{
UBYTE *hdr = v->Txhdr;
short n;
USHORT crc;
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "zshhdr: %s %lx\n", frametypes[type + FTOFFSET],
v->Rxbytes);
dlog(v, v->Msgbuf);
#endif
sendline(v, ZPAD);
sendline(v, ZPAD);
sendline(v, ZDLE);
sendline(v, ZHEX);
zputhex(v, (UBYTE) type);
v->Crc32t = 0;
crc = updcrc(type, 0);
for (n = 4; --n >= 0; )
{
zputhex(v, *hdr);
crc = updcrc(((USHORT) (*hdr++)), crc);
}
crc = updcrc(((USHORT) 0), crc);
crc = updcrc(((USHORT) 0), crc);
zputhex(v, (UBYTE) (crc >> 8));
zputhex(v, (UBYTE) crc);
/* Make it printable on remote machine */
sendline(v, '\r');
sendline(v, '\n');
/* Uncork the remote in case a fake XOFF has stopped data flow */
if (type != ZFIN)
sendline(v, XON);
} /* End of void zshhdr() */
/**********************************************************
* void zsdata() and void zsda32()
*
* Send binary array buf of length length, with ending
* ZDLE sequence frameend
**********************************************************/
void zsdata(struct Vars *v, short length, USHORT frameend)
{
UBYTE *buf, *outptr, c;
USHORT crc;
ULONG crc32;
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, v->Crc32t ? "zsda32: length=%ld end=%lx\n"
: "zsdata: length=%ld end=%lx\n", (long) length, (long) frameend);
dlog(v, v->Msgbuf);
#endif
buf = v->Pktbuf;
outptr = v->Outbuf + v->Outbuflen;
crc32 = 0xFFFFFFFFL; /* zsda32() */
crc = 0;
while (--length >= 0)
{
switch (DLE_actions[c = *buf])
{
case 2:
if (v->Lastzsent != '@')
goto sendit;
/* Fallthrough */
case 1:
*outptr++ = ZDLE;
c ^= 0x40;
sendit:
case 0:
*outptr++ = v->Lastzsent = c;
}
if (v->Crc32t) /* zsda32() */
crc32 = UPDC32((0xFF & *buf++), crc32);
else
crc = updcrc(((USHORT) (*buf++)), crc);
}
*outptr++ = ZDLE;
*outptr++ = frameend;
v->Outbuflen = outptr - v->Outbuf;
if (v->Crc32t) /* zsda32() */
{
crc32 = UPDC32(frameend, crc32);
crc32 = ~crc32;
for (length = 4; --length >= 0; )
{
zsendline(v, (int) crc32);
crc32 >>= 8;
}
}
else
{
crc = updcrc(frameend, crc);
crc = updcrc(((USHORT) 0), crc);
crc = updcrc(((USHORT) 0), crc);
zsendline(v, (UBYTE) (crc >> 8));
zsendline(v, (UBYTE) crc);
}
if (frameend == ZCRCW)
xsendline(v, XON);
} /* End of void zsdata() */
/**********************************************************
* short zrdata(struct Vars *v, UBYTE *buf, short length)
*
* Receive array buf of max length with ending ZDLE sequence
* and CRC-16. Returns the ending character or error code.
**********************************************************/
short zrdata(struct Vars *v, UBYTE *buf, short length)
{
short c, d;
USHORT crc;
if (v->Rxframeind == ZBIN32)
return zrdat32(v, buf, length);
crc = v->Rxcount = 0;
for (;;)
{
if ((c = zdlread(v)) & ~0xFF)
{
crcfoo:
switch (c)
{
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
crc = updcrc(((d = c) & 0xFF), crc);
if ((c = zdlread(v)) & ~0xFF)
goto crcfoo;
crc = updcrc(c, crc);
if ((c = zdlread(v)) & ~0xFF)
goto crcfoo;
crc = updcrc(c, crc);
if (crc & 0xFFFF)
{
strcpy(v->Msgbuf, "Bad data packet CRC-16 ");
return ERROR;
}
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "zrdata: cnt = %ld ret = %lx\n",
(long) v->Rxcount, (long) d);
dlog(v, v->Msgbuf);
#endif
return d;
case GOTCAN:
strcpy(v->Msgbuf, "Sender canceled ");
return ZCAN;
case TIMEOUT:
strcpy(v->Msgbuf, "Data packet timeout ");
return c;
case RCDO:
return c;
default:
strcpy(v->Msgbuf, "Unrecognizable data packet ");
return c;
}
}
if (--length < 0)
{
strcpy(v->Msgbuf, "Data packet too long ");
return ERROR;
}
++v->Rxcount;
*buf++ = c;
crc = updcrc(c, crc);
continue;
}
} /* End of short zrdata() */
/**********************************************************
* short zrdat32(struct Vars *v, UBYTE *buf, short length)
*
* Receive array buf of max length with ending ZDLE sequence
* and CRC-32. Returns the ending character or error code.
**********************************************************/
short zrdat32(struct Vars *v, UBYTE *buf, short length)
{
short c, d;
ULONG crc32;
crc32 = 0xFFFFFFFFL;
v->Rxcount = 0;
for (;;)
{
if ((c = zdlread(v)) & ~0xFF)
{
crcfoo:
switch (c)
{
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
d = c;
c &= 0xFF;
crc32 = UPDC32(c, crc32);
if ((c = zdlread(v)) & ~0xFF)
goto crcfoo;
crc32 = UPDC32(c, crc32);
if ((c = zdlread(v)) & ~0xFF)
goto crcfoo;
crc32 = UPDC32(c, crc32);
if ((c = zdlread(v)) & ~0xFF)
goto crcfoo;
crc32 = UPDC32(c, crc32);
if ((c = zdlread(v)) & ~0xFF)
goto crcfoo;
crc32 = UPDC32(c, crc32);
if (crc32 != 0xDEBB20E3)
{
strcpy(v->Msgbuf, "Bad data packet CRC-32 ");
return ERROR;
}
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "zrdat32: cnt = %ld ret = %lx\n",
(long) v->Rxcount, (long) d);
dlog(v, v->Msgbuf);
#endif
return d;
case GOTCAN:
strcpy(v->Msgbuf, "Sender canceled ");
return ZCAN;
case TIMEOUT:
strcpy(v->Msgbuf, "Data packet timeout ");
return c;
case RCDO:
return c;
default:
strcpy(v->Msgbuf, "Unrecognizable data packet ");
return c;
}
}
if (--length < 0)
{
strcpy(v->Msgbuf, "Data packet too long ");
return ERROR;
}
++v->Rxcount;
*buf++ = c;
crc32 = UPDC32(c, crc32);
continue;
}
} /* End of short zrdat32() */
/**********************************************************
* short zgethdr(struct Vars *v)
*
* Read a ZMODEM header to hdr, either binary or hex.
* On success return type of header.
* Otherwise return negative on error.
**********************************************************/
short zgethdr(struct Vars *v)
{
short c, cancount;
long n;
#ifdef DEBUGLOG
UBYTE msgbuf [128];
#endif
n = v->Baud; /* Max characters before start of frame */
cancount = 5;
again:
v->Rxframeind = v->Rxtype = 0;
switch (c = noxrd7(v))
{
case RCDO:
case TIMEOUT:
goto fifi;
case CAN:
if (--cancount <= 0)
{
c = ZCAN;
goto fifi;
}
default:
agn2:
if (--n <= 0)
{
strcpy(v->Msgbuf, "Header search garbage count exceeded ");
return ERROR;
}
if (c != CAN)
cancount = 5;
goto again;
case ZPAD: /* This is what we want. */
break;
}
cancount = 5;
splat:
switch (c = noxrd7(v))
{
case ZPAD:
goto splat;
case RCDO:
case TIMEOUT:
goto fifi;
default:
goto agn2;
case ZDLE: /* This is what we want. */
break;
}
switch (c = noxrd7(v))
{
case RCDO:
case TIMEOUT:
goto fifi;
case ZBIN:
v->Rxframeind = ZBIN;
v->Crc32 = FALSE;
c = zrbhdr(v);
break;
case ZBIN32:
v->Crc32 = v->Rxframeind = ZBIN32;
c = zrbhdr32(v);
break;
case ZHEX:
v->Rxframeind = ZHEX;
v->Crc32 = FALSE;
c = zrhhdr(v);
break;
case CAN:
if (--cancount <= 0)
{
c = ZCAN;
goto fifi;
}
goto agn2;
default:
goto agn2;
}
v->Rxpos = rclhdr(v);
fifi:
switch (c)
{
case GOTCAN:
c = ZCAN;
case ZNAK:
case ZCAN:
case ERROR:
case TIMEOUT:
case RCDO:
mysprintf(v->Msgbuf, "%s %s ", frametypes[c + FTOFFSET],
(c >= 0) ? "header" : "error");
#ifdef DEBUGLOG
default:
if (c >= -3 && c <= FRTYPES)
mysprintf(msgbuf, "zgethdr: %s @ %ld\n", frametypes[c + FTOFFSET],
v->Rxpos);
else
mysprintf(msgbuf, "zgethdr: Unknown type %ld @ %ld\n", (long) c,
v->Rxpos);
dlog(v, msgbuf);
#endif
}
return c;
} /* End of short zgethdr() */
/**********************************************************
* short zrbhdr(struct Vars *v)
*
* Receive a binary style header (type and position)
**********************************************************/
short zrbhdr(struct Vars *v)
{
UBYTE *hdr = v->Rxhdr;
short c, n;
USHORT crc;
if ((c = zdlread(v)) & ~0xFF)
return c;
v->Rxtype = c;
crc = updcrc(c, 0);
for (n = 4; --n >= 0; )
{
if ((c = zdlread(v)) & ~0xFF)
return c;
crc = updcrc(c, crc);
*hdr++ = c;
}
if ((c = zdlread(v)) & ~0xFF)
return c;
crc = updcrc(c, crc);
if ((c = zdlread(v)) & ~0xFF)
return c;
crc = updcrc(c, crc);
if (crc & 0xFFFF)
{
strcpy(v->Msgbuf, "Bad Header CRC-16 ");
return ERROR;
}
return v->Rxtype;
} /* End of short zrbhdr() */
/**********************************************************
* short zrbhdr32(struct Vars *v)
*
* Receive a binary style header (type and position) with
* 32 bit FCS
**********************************************************/
short zrbhdr32(struct Vars *v)
{
UBYTE *hdr = v->Rxhdr;
short c, n;
ULONG crc32;
if ((c = zdlread(v)) & ~0xFF)
return c;
v->Rxtype = c;
crc32 = 0xFFFFFFFFL;
crc32 = UPDC32(c, crc32);
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "zrbhdr32: c=%x crc32=%1x\n", c, crc32);
dlog(v, v->Msgbuf);
#endif
for (n = 4; --n >= 0; )
{
if ((c = zdlread(v)) & ~0xFF)
return c;
crc32 = UPDC32(c, crc32);
*hdr++ = c;
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "zrbhdr32: c=%x crc32=%1x\n", c, crc32);
dlog(v, v->Msgbuf);
#endif
}
for (n = 4; --n >= 0; )
{
if ((c = zdlread(v)) & ~0xFF)
return c;
crc32 = UPDC32(c, crc32);
#ifdef DEBUGLOG
mysprintf(v->Msgbuf, "zrbhdr32: c=%x crc32=%1x\n", c, crc32);
dlog(v, v->Msgbuf);
#endif
}
if (crc32 != 0xDEBB20E3)
{
strcpy(v->Msgbuf, "Bad Header CRC-32 ");
return ERROR;
}
return v->Rxtype;
} /* End of short zrbhdr32() */
/**********************************************************
* short zrhhdr(struct Vars *v)
*
* Receive a hex style header (type and position)
**********************************************************/
short zrhhdr(struct Vars *v)
{
UBYTE *hdr = v->Rxhdr;
short c, n;
USHORT crc;
if ((c = zgethex(v)) < 0)
return c;
v->Rxtype = c;
crc = updcrc(c, 0);
for (n = 4; --n >= 0; )
{
if ((c = zgethex(v)) < 0)
return c;
crc = updcrc(c, crc);
*hdr++ = c;
}
if ((c = zgethex(v)) < 0)
return c;
crc = updcrc(c, crc);
if ((c = zgethex(v)) < 0)
return c;
crc = updcrc(c, crc);
if (crc & 0xFFFF)
{
strcpy(v->Msgbuf, "Bad Header CRC ");
return ERROR;
}
if (readock(v, 1) == '\r')
readock(v, 1); /* Throw away possible cr/lf */
return v->Rxtype;
} /* End of short zrhhdr() */
/**********************************************************
* void zputhex(struct Vars *v, UBYTE c)
*
* Send a byte as two hex digits
**********************************************************/
void zputhex(struct Vars *v, UBYTE c)
{
static char digits[] = "0123456789abcdef";
sendline(v, digits[(c >> 4) & 0x0F]);
sendline(v, digits[c & 0x0F]);
} /* End of void zputhex() */
/**********************************************************
* void zsendline(struct Vars *v, UBYTE c)
*
* Send character c with ZMODEM escape sequence encoding.
* Escape ZDLE, real DLE, XON, XOFF, and CR following @ (Telenet net escape)
**********************************************************/
void zsendline(struct Vars *v, UBYTE c)
{
switch (DLE_actions[c])
{
case 2:
if (v->Lastzsent != '@')
goto sendit;
/* Fallthrough */
case 1:
xsendline(v, ZDLE);
c ^= 0x40;
sendit:
case 0:
xsendline(v, v->Lastzsent = c);
}
} /* End of void zsendline() */
/**********************************************************
* short zgethex(struct Vars *v)
*
* Decode two lower case hex digits into an 8 bit byte value
**********************************************************/
short zgethex(struct Vars *v)
{
short c, n;
if ((n = noxrd7(v)) < 0)
return n;
n -= '0';
if (n > 9)
n -= ('a' - ':');
if (n & ~0xF)
return ERROR;
if ((c = noxrd7(v)) < 0)
return c;
c -= '0';
if (c > 9)
c -= ('a' - ':');
if (c & ~0xF)
return ERROR;
return (short) (n << 4 | c);
} /* End of short zgethex() */
/**********************************************************
* short zdlread(struct Vars *v)
*
* Read a byte, checking for ZMODEM escape encoding
* including CAN*5 which represents a quick abort.
**********************************************************/
short zdlread(struct Vars *v)
{
short c;
if ((c = readock(v, v->Rxtimeout)) != ZDLE)
return c;
if ((c = readock(v, v->Rxtimeout)) < 0)
return c;
if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0)
return c;
if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0)
return c;
if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0)
return c;
switch (c)
{
case CAN:
return GOTCAN;
case ZCRCE:
case ZCRCG:
case ZCRCQ:
case ZCRCW:
return (short) (c | GOTOR);
case ZRUB0:
return 0x7F;
case ZRUB1:
return 0xFF;
default:
if ((c & 0x60) == 0x40)
return (short) (c ^ 0x40);
break;
}
strcpy(v->Msgbuf, "Bad ZMODEM escape sequence ");
return ERROR;
} /* End of short zdlread() */
/**********************************************************
* short noxrd7(struct Vars *v)
*
* Read a character from the modem line with timeout.
* Eat parity, XON and XOFF characters.
**********************************************************/
short noxrd7(struct Vars *v)
{
short c;
for (;;)
{
if ((c = readock(v, v->Rxtimeout)) < 0)
return c;
switch (c &= 0x7F)
{
case XON:
case XOFF:
continue;
default:
return c;
}
}
} /* short noxrd7() */
/**********************************************************
* void stohdr(struct Vars *v, long pos)
*
* Store long integer pos in Txhdr
**********************************************************/
void stohdr(struct Vars *v, long pos)
{
v->Txhdr[ZP0] = pos;
pos >>= 8;
v->Txhdr[ZP1] = pos;
pos >>= 8;
v->Txhdr[ZP2] = pos;
pos >>= 8;
v->Txhdr[ZP3] = pos;
} /* End of void stohdr() */
/**********************************************************
* long rclhdr(struct Vars *v)
*
* Recover a long integer from a header
**********************************************************/
long rclhdr(struct Vars *v)
{
long l;
l = v->Rxhdr[ZP3];
l = (l << 8) | v->Rxhdr[ZP2];
l = (l << 8) | v->Rxhdr[ZP1];
l = (l << 8) | v->Rxhdr[ZP0];
return l;
} /* End of long rclhdr() */
/* End of Zm.c source */